﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Web.UI;

using SBPweb.Data;

using SBPweb.PROvibe.Business.Entities;
using SBPweb.PROvibe.Business.Modularity;

namespace SBPweb.PROvibe.Business.Modularity
{
    public class ModuleLoader
    {

        #region Private members

        private static Dictionary<string, ConstructorInfo> mModuleConstructors;

        #endregion

        #region Constructor logic

        static ModuleLoader()
        {
            mModuleConstructors = new Dictionary<string, ConstructorInfo>();
        }

        #endregion

        #region Public functions

        internal static ConstructorInfo GetConstructorInfo(Entities.Module entity, string moduleTypeName)
        {
            Assembly asm;

            try
            {
                asm = Assembly.Load(entity.AssemblyStream.RawData);

                Type type = asm.GetType(moduleTypeName);
                return type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Entities.Module) }, null);
            }
            catch (Exception ex)
            {
                LogManager.WriteCritical(entity, ex, "ModuleLoader");
                return null;
            }
        }

        public static IModule CreateModuleInstance(Entities.Module entity, string moduleTypeName)
        {
            ConstructorInfo constructorInfo;

            lock (mModuleConstructors)
            {
                if (mModuleConstructors.ContainsKey(moduleTypeName))
                {
                    constructorInfo = mModuleConstructors[moduleTypeName];
                }
                else
                {
                    constructorInfo = GetConstructorInfo(entity, moduleTypeName);
                    mModuleConstructors.Add(moduleTypeName, constructorInfo);
                }
            }
            
            IModule ret = null;

            try
            {
                ret = (IModule)constructorInfo.Invoke(new object[] { entity });
            }
            catch (Exception ex)
            {
                LogManager.WriteCritical(entity, ex, "ModuleLoader");
                return null;
            }

            return ret;
        }

        public static Control AddAsControl(IModule module, Control parent)
        {
            if (!(module is Control) || !(typeof(Control).IsAssignableFrom(module.GetType())))
            {
                throw new ArgumentException("Module is not a UserControl!");
            }
            Control c = (Control)module;

            parent.Controls.Add(c);

            return c;
        }

        #endregion

    }
}